import React, {
  createElement,
  useEffect,
  useImperativeHandle,
  memo,
} from 'react';
import PropTypes from 'prop-types';
import {
  Form,
  Input,
  Select,
  DatePicker,
  Radio,
  Checkbox,
  InputNumber,
  Row,
  Col,
} from 'antd';
import UploadControl from './Upload';

const FormItem = Form.Item,
  { Password } = Input,
  h = createElement;

const MyForm = ({ columns, obj, cRef }) => {
  //通过Form.useForm对表单数据域进行交互。useForm是React Hooks的实现，只能用于函数组件
  const [form] = Form.useForm();

  //cRef就是父组件传过来的ref
  useImperativeHandle(cRef, () => ({
    //validForm就是暴露给父组件的方法
    validForm: () => {
      return form.validateFields();
    },
  }));

  //form表单的回显
  useEffect(() => {
    form.resetFields();
    // 将有值obj传入form，文件除外
    const newObj = {};
    _.forIn(obj, (value, key) => {
      const column = _.find(columns, { name: key });
      if (column) {
        if (column.type !== 'upload') {
          newObj[key] = value;
        }
      }
    });
    form.setFieldsValue(newObj);
  }, [obj]);

  // 组件工厂
  const components = {
    select: ({ name, label, list = [] }) =>
      h(
        Select,
        { placeholder: label },
        list.map((c, i) =>
          h(Select.Option, { key: `${name}_${i}`, value: c.value }, c.label),
        ),
      ),
    input: ({ label }) => <Input placeholder={label} />,
    number: ({ label, max, min }) => (
      <InputNumber max={max} min={min} placeholder={label} />
    ),
    hidden: () => <Input type="hidden" />,
    disabled: () => <Input disabled />,
    password: ({ label }) => h(Password, { placeholder: label }),
    datePicker: ({ label }) => (
      <DatePicker placeholder={label} format="YYYY-MM-DD" />
    ),
    radioGroup: ({ name, list = [] }) =>
      h(
        Radio.Group,
        {},
        list.map((c, i) =>
          h(Radio, { key: `${name}_${i}`, value: c.value }, c.label),
        ),
      ),
    checkGroup: ({ list = [] }) => <Checkbox.Group options={list} />,
    upload: ({ name }) => {
      return (
        <UploadControl
          img={obj[name] ? obj[name] : null}
          callback={(src) => {
            const _obj = {};
            _obj[name] = src;
            form.setFieldsValue(_obj);
          }}
        />
      );
    },
  };

  return (
    <Form labelCol={{ style: { width: 70 } }} preserve={false} form={form}>
      <Row gutter={16}>
        {columns &&
          columns.map((n, i) => {
            const { type = 'input' } = n,
              factory = components[type];

            let span = 12;
            if (type === 'hidden') {
              span = 0;
            } else {
              span = n.colSpan || 12;
            }

            return (
              <Col span={span} key={i}>
                <FormItem {...n} key={n.name} hidden={type === 'hidden'}>
                  {factory(n)}
                </FormItem>
              </Col>
            );
          })}
      </Row>
    </Form>
  );
};

MyForm.propTypes = {
  columns: PropTypes.array.isRequired,
  obj: PropTypes.object,
  cRef: PropTypes.object,
};

export default memo(MyForm);
